home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AOL File Library: 2,801 to 2,900
/
aol-file-protocol-4400-2801-to-2900.zip
/
AOLDLs
/
C++ Files Library
/
CWASTE C++ text editing routi
/
CWASTE folder.sit
/
CWASTE folder
/
WASTE4.c
< prev
next >
Wrap
Text File
|
1994-07-20
|
28KB
|
1,147 lines
//unit WASTE4;
// { WASTE PROJECT: }
// { Unit Four: Editing }
// { Copyright ⌐ 1993-1994 Marco Piovanelli }
// { All Rights Reserved }
// C conversion by Dan Crevier
#include "WASTEIntf.h"
OSErr _WEInsertRun(long runIndex, long offset, long styleIndex, WEPtr pWE)
{
// { Insert a new element in the style run array, at the specified runIndex position. }
// { The new element consists of the pair <offset, styleIndex>. }
RunArrayElement element;
OSErr err;
// _WEInsertRun = noErr;
// { prepare the element record to be inserted in the array }
element.runStart = offset;
element.styleIndex = styleIndex;
// { do the insertion }
err = _WEInsertSlot((Handle)pWE->hRuns, (Ptr)&element, runIndex + 1, sizeof(element));
if (err != noErr)
{
return err;
}
// { increment style run count }
pWE->nRuns = pWE->nRuns + 1;
// { increment the reference count field of the style table element }
// { referenced by the newly inserted style run }
(*pWE->hStyles)[styleIndex].refCount = (*pWE->hStyles)[styleIndex].refCount + 1;
return noErr;
}
OSErr _WERemoveRun(long runIndex, WEPtr pWE)
{
// { remove the specified element from the style run array }
long styleIndex;
OSErr err;
styleIndex = (*pWE->hRuns)[runIndex].styleIndex;
// { do the removal (errors returned by _WERemoveSlot can be safely ignored) }
err = _WERemoveSlot((Handle)pWE->hRuns, runIndex, sizeof(RunArrayElement));
// { decrement style run count }
pWE->nRuns = pWE->nRuns - 1;
// { decrement the reference count field of the style table element }
// { that was referenced by the style run we have just removed }
(*pWE->hStyles)[styleIndex].refCount = (*pWE->hStyles)[styleIndex].refCount - 1;
return err;
}
void _WEChangeRun(long runIndex, long newStyleIndex, WEPtr pWE)
{
// { change the styleIndex field of the specified element of the style run array }
long oldStyleIndex;
// { do the change }
oldStyleIndex = (*pWE->hRuns)[runIndex].styleIndex;
(*pWE->hRuns)[runIndex].styleIndex = newStyleIndex;
// { decrement the reference count field of the old style table element }
(*pWE->hStyles)[oldStyleIndex].refCount = (*pWE->hStyles)[oldStyleIndex].refCount - 1;
// { increment the reference count field of the new style table element }
(*pWE->hStyles)[newStyleIndex].refCount = (*pWE->hStyles)[newStyleIndex].refCount + 1;
}
OSErr _WENewStyle(WERunAttributes *ts, long *styleIndex, WEPtr pWE)
{
// { given the specified WERunAttributes record, find the corresponding entry }
// { in the style table (create a new entry if necessary), and return its index }
StyleTablePtr pTable;
StyleTableElement element;
long index, unusedIndex;
OSErr err;
// _WENewStyle = noErr;
pTable = *pWE->hStyles;
// { see if the given style already exists in the style table }
// { while scanning the table, also remember the position of the first unused style, if any }
index = 0;
unusedIndex = -1;
while (index < pWE->nStyles)
{
// { perform a bitwise comparison between the current element and the specified style }
if (_WEBlockCmp((Ptr)&pTable[index].info, (Ptr)ts, sizeof(WERunAttributes)))
{
*styleIndex = index; // { found: style already present }
return noErr;
}
// { check for entries which aren't referenced and can be recycled }
if (pTable[index].refCount == 0)
{
unusedIndex = index;
}
index = index + 1;
} // { while }
// { the specified style doesn't exist in the style table }
// { see if we can recycle an unused entry }
if (unusedIndex >= 0)
{
index = unusedIndex;
pTable[index].info = *ts;
}
else
{
// { no reusable entry: we have to append a new element to the table }
element.refCount = 0;
element.info = *ts;
err = _WEInsertSlot((Handle)pWE->hStyles, (Ptr)&element, index, sizeof(element));
if (err != noErr)
{
return err;
}
// { update style count in the WE record }
pWE->nStyles = index + 1;
}
// { return the index to the new element }
*styleIndex = index;
return noErr;
}
OSErr _WERedraw(long rangeStart, long rangeEnd, WEHandle hWE)
{
// { the WE record is guaranteed to be already locked }
WEPtr pWE;
LineArrayPtr pLines;
long startLine, endLine;
long oldTextHeight, newTextHeight;
LongRect r;
Rect viewRect, updateRect;
RgnHandle saveClip;
GrafPtr savePort;
OSErr err;
pWE = *hWE;
// { do nothing if recalculation has been inhibited }
if (!BTST(pWE->flags, weFInhibitRecal))
{
// { hide the caret }
if (BTST(pWE->flags, weFCaretVisible))
{
_WEDrawCaret(hWE);
}
// { remember total text height }
oldTextHeight = pWE->destRect.bottom - pWE->destRect.top;
// { find line range affected by modification }
startLine = _WEOffsetToLine(rangeStart, hWE);
endLine = _WEOffsetToLine(rangeEnd, hWE);
// { recalculate line breaks starting from startLine }
err = _WERecalBreaks(&startLine, &endLine, hWE);
if (err != noErr)
{
goto cleanup;
}
// { recalculate slops }
_WERecalSlops(startLine, endLine, hWE);
// { calculate new total text height }
newTextHeight = pWE->destRect.bottom - pWE->destRect.top;
// { calculate the rectangle to redraw (in long coordinates) }
r.left = -SHRT_MAX;
r.right = SHRT_MAX;
pLines = *pWE->hLines;
r.top = pLines[startLine].lineOrigin;
// { if total text height hasn't changed, it's enough to redraw lines up to endLine }
// { otherwise we must redraw all lines from startLine on }
if ((newTextHeight == oldTextHeight) && (endLine < pWE->nLines - 1))
{
r.bottom = pLines[endLine + 1].lineOrigin;
}
else if (newTextHeight < oldTextHeight)
{
r.bottom = oldTextHeight;
}
else
{
r.bottom = newTextHeight;
}
WEOffsetLongRect(&r, 0, pWE->destRect.top);
// { calculate the intersection between this rectangle and the view rectangle }
WELongRectToRect(&r, &updateRect);
WELongRectToRect(&pWE->viewRect, &viewRect);
if (SectRect(&updateRect, &viewRect, &updateRect))
{
// { set up the port and the clip region }
GetPort(&savePort);
SetPort(pWE->port);
// { set the clip region to updateRect }
saveClip = NewRgn();
GetClip(saveClip);
ClipRect(&updateRect);
// { we only really need to redraw the visible lines }
startLine = _WEPixelToLine(updateRect.top - pWE->destRect.top, hWE);
endLine = _WEPixelToLine(updateRect.bottom - pWE->destRect.top - 1, hWE);
// { redraw the lines (pass TRUE in the doErase parameter) }
_WEDrawLines(startLine, endLine, true, hWE);
// { erase the portion of the update rectangle below the last line (if any) }
pLines = *pWE->hLines;
updateRect.top = pWE->destRect.top + pLines[endLine + 1].lineOrigin;
if (updateRect.top < updateRect.bottom)
{
EraseRect(&updateRect);
}
// { restore the clip region }
SetClip(saveClip);
DisposeRgn(saveClip);
// { restore the port }
SetPort(savePort);
// { redraw the caret or the selection range }
if (pWE->selStart < pWE->selEnd)
{
_WEHiliteRange(pWE->selStart, pWE->selEnd, hWE);
}
else
{
_WEDrawCaret(hWE);
}
} // { if SectRect }
// { scroll the selection range into view }
WESelView(hWE);
} // { if recal not inhibited }
// { clear result code }
err = noErr;
cleanup:
// { return result code }
return err;
}
OSErr _WESetStyleRange(long rangeStart, long rangeEnd, short mode, WETextStyle *ts, WEHandle hWE)
{
// { alter the style attributes of the specified text range according to ts and mode }
// { the WE record is guaranteed to be already locked }
WEPtr pWE;
RunArrayHandle hRuns;
long offset;
long runIndex;
long oldStyleIndex, newStyleIndex;
WERunInfo runInfo;
short temp;
char continuousStyles;
OSErr err;
pWE = *hWE;
hRuns = pWE->hRuns;
// { if mode contains weDoToggleFace, we need to determine which QuickDraw styles }
// { are continuous over the specified text range: those styles must be turned off }
if (BTST(mode, kModeToggleFace))
{
temp = weDoFace;
_WEContinuousStyleRange(rangeStart, rangeEnd, &temp, &runInfo.runAttrs.runStyle, hWE);
continuousStyles = runInfo.runAttrs.runStyle.tsFace;
}
else
{
continuousStyles = 0;
}
// { find the index to the first style run in the specified range }
offset = rangeStart;
runIndex = _WEOffsetToRun(offset, hWE);
// { run thru all the style runs that encompass the selection range }
do
{
// { find style index for this run and retrieve corresponding style attributes }
oldStyleIndex = (*hRuns)[runIndex].styleIndex;
_WEGetIndStyle(runIndex, &runInfo, hWE);
// { _WEGetIndStyle returns textLength + 1 in runInfo.runEnd for the last style run: }
// { correct this anomaly (which is useful for other purposes, anyway) }
if (runInfo.runEnd > pWE->textLength)
{
runInfo.runEnd = pWE->textLength;
}
// { apply changes to existing style attributes as requested }
_WECopyStyle(ts, &runInfo.runAttrs.runStyle, continuousStyles, mode);
// { recalculate font metrics, if necessary }
if ((mode & (weDoFont + weDoSize + weDoFace + weDoAddSize)) != 0)
{
_WEFillFontInfo(pWE->port, &runInfo.runAttrs);
}
// { get a style index for the new attributes }
err = _WENewStyle(&runInfo.runAttrs, &newStyleIndex, pWE);
if (err != noErr)
{
goto cleanup;
}
// { if offset falls on a style boundary and this style run has become identical }
// { to the previous one, merge the two runs together }
if ((offset == runInfo.runStart) && (runIndex > 0) &&
((*hRuns)[runIndex - 1].styleIndex == newStyleIndex))
{
err = _WERemoveRun(runIndex, pWE);
if (err != noErr)
{
goto cleanup;
}
runIndex = runIndex - 1;
}
// { style index changed? }
if (oldStyleIndex != newStyleIndex)
{
// { if offset is in the middle of a style run, insert a new style run in the run array }
if (offset > runInfo.runStart)
{
err = _WEInsertRun(runIndex, offset, newStyleIndex, pWE);
if (err != noErr)
{
goto cleanup;
}
runIndex = runIndex + 1;
}
else
{
// { otherwise just change the styleIndex field of the current style run element }
_WEChangeRun(runIndex, newStyleIndex, pWE);
}
// { if specified range ends in the middle of a style run, insert yet another element }
if (rangeEnd < runInfo.runEnd)
{
err = _WEInsertRun(runIndex, rangeEnd, oldStyleIndex, pWE);
if (err != noErr)
{
goto cleanup;
}
}
} // { if oldStyle != newStyle }
// { go to next style run }
runIndex = runIndex + 1;
offset = runInfo.runEnd;
} while (offset < rangeEnd);
// { if the last style run ends exactly at the end of the specified range, }
// { see if we can merge it with the following style run }
if ((offset == rangeEnd) && (runIndex < pWE->nRuns) &&
((*hRuns)[runIndex].styleIndex == newStyleIndex))
{
err = _WERemoveRun(runIndex, pWE);
if (err != noErr)
{
goto cleanup;
}
}
// { clear result code }
err = noErr;
cleanup:
// { return result code }
return err;
}
OSErr _WEApplyStyleScrap(long rangeStart, long rangeEnd, WEStyleScrapHandle styleScrap, WEHandle hWE)
{
// { apply the given style scrap to the specified text range }
// { the WE record is guaranteed to be already locked }
WEPtr pWE;
WEStyleScrapPeek pElement;
long runStart, runEnd;
short index, lastElement;
WETextStyle ts;
OSErr err;
// _WEApplyStyleScrap = noErr;
pWE = *hWE;
// { loop through each element of the style scrap }
lastElement = (*styleScrap)->scrpNStyles - 1;
for(index = 0; index<=lastElement; index++)
{
// { get a pointer to the current scrap element }
pElement = (WEStyleScrapPeek)&(*styleScrap)->scrpStyleTab[index];
// { calculate text run to which this element is to be applied }
runStart = rangeStart + pElement->first.scrpStartChar;
if (index < lastElement)
{
runEnd = rangeStart + pElement->second.scrpStartChar;
}
else
{
runEnd = rangeEnd;
}
// { perform some range checking }
if (runEnd > rangeEnd)
{
runEnd = rangeEnd;
}
if (runStart >= runEnd)
{
continue;
}
// { copy style to a local variable in case memory moves }
ts = pElement->first.scrpAttrs.runStyle;
// { apply the specified style to the range }
err = _WESetStyleRange(runStart, runEnd, weDoAll + weDoReplaceFace, &ts, hWE);
if (err != noErr)
{
return err;
}
}
return noErr;
}
void _WEBumpRunStart(long runIndex, long deltaRunStart, WEPtr pWE)
{
// { add deltaLineStart to the lineStart field of all line records }
// { starting from lineIndex }
long *pStart;
long nRuns;
pStart = &(*pWE->hRuns)[runIndex].runStart;
nRuns = pWE->nRuns;
// { loop through the style run array adjusting the runStart fields }
while (runIndex <= nRuns)
{
*pStart = *pStart + deltaRunStart;
pStart = (long *)((long)(pStart) + sizeof(RunArrayElement));
runIndex = runIndex + 1;
}
}
OSErr _WERemoveRunRange(long rangeStart, long rangeEnd, WEHandle hWE)
{
// { the range of text between rangeStart and rangeEnd is being deleted }
// { update the style run array (and the style table) accordingly }
// { the WE handle must be locked on entry }
WEPtr pWE;
RunArrayPeek pRuns;
long startRun, endRun;
OSErr err;
pWE = *hWE;
// { find the index to the first and last style runs in the specified range }
startRun = _WEOffsetToRun(rangeStart, hWE);
endRun = _WEOffsetToRun(rangeEnd, hWE) - 1;
// { remove all style runs between startRun and endRun }
while (endRun > startRun)
{
err = _WERemoveRun(endRun, pWE);
if (err != noErr)
{
goto cleanup;
}
endRun = endRun - 1;
}
// { move back all subsequent style runs }
_WEBumpRunStart(startRun + 1, rangeStart - rangeEnd, pWE);
if ((endRun == startRun) && (endRun < pWE->nRuns - 1))
{
pRuns = (RunArrayPeek)&(*pWE->hRuns)[endRun];
pRuns->second.runStart = rangeStart;
}
// { remove the first style run if is has become zero length }
pRuns = (RunArrayPeek)&(*pWE->hRuns)[startRun];
if (pRuns->first.runStart == pRuns->second.runStart)
{
err = _WERemoveRun(startRun, pWE);
if (err != noErr)
{
goto cleanup;
}
startRun = startRun - 1;
}
// { merge the first and last runs if they have the same style index }
if (startRun >= 0)
{
pRuns = (RunArrayPeek)&(*pWE->hRuns)[startRun];
if (pRuns->first.styleIndex == pRuns->second.styleIndex)
{
err = _WERemoveRun(startRun + 1, pWE);
if (err != noErr)
{
goto cleanup;
}
}
}
// { clear result code }
err = noErr;
cleanup:
// { return result code }
return err;
}
void _WEBumpLineStart(long lineIndex, long deltaLineStart, WEPtr pWE)
{
// { add deltaLineStart to the lineStart field of all line records }
// { starting from lineIndex }
long *pStart;
long nLines;
pStart = &(*pWE->hLines)[lineIndex].lineStart;
nLines = pWE->nLines;
// { loop through the line array adjusting the lineStart fields }
while (lineIndex <= nLines)
{
*pStart = *pStart + deltaLineStart;
pStart = (long *)((long)pStart + sizeof(LineRec));
lineIndex = lineIndex + 1;
}
}
OSErr _WERemoveLineRange(long rangeStart, long rangeEnd, WEHandle hWE)
{
// { the range of text between rangeStart and rangeEnd is being deleted }
// { update the line array accordingly }
// { the WE handle must be locked on entry }
WEPtr pWE;
long startLine, endLine;
OSErr err;
// _WERemoveLineRange = noErr;
pWE = *hWE;
// { remove all line records between rangeStart and rangeEnd }
startLine = _WEOffsetToLine(rangeStart, hWE) + 1;
endLine = _WEOffsetToLine(rangeEnd, hWE);
while (endLine >= startLine)
{
err = _WERemoveLine(endLine, pWE);
if (err != noErr)
{
return err;
}
endLine = endLine - 1;
} // { while }
// { update the lineStart field of all the line records that follow }
_WEBumpLineStart(startLine, rangeStart - rangeEnd, pWE);
return noErr;
}
OSErr _WEDeleteRange(long rangeStart, long rangeEnd, WEHandle hWE)
{
// { used internally to delete a text range }
// { if saveNullStyle is TRUE, the first style in the range is saved in nullStyle }
// { the WE record is guaranteed to be already locked }
WEPtr pWE;
WERunInfo runInfo;
long oldTextLength, newTextLength;
long pText;
OSErr err;
pWE = *hWE;
// { do nothing if the specified range is empty }
if (rangeStart == rangeEnd)
{
goto cleanup1;
}
// { save the first style in the specified range in nullStyle }
WEGetRunInfo(rangeStart, &runInfo, hWE);
pWE->nullStyle = runInfo.runAttrs;
BSET(pWE->flags, weFUseNullStyle);
// { remove all line records between rangeStart and rangeEnd }
err = _WERemoveLineRange(rangeStart, rangeEnd, hWE);
if (err != noErr)
{
goto cleanup2;
}
// { remove all style runs between rangeStart and rangeEnd }
err = _WERemoveRunRange(rangeStart, rangeEnd, hWE);
if (err != noErr)
{
goto cleanup2;
}
// { calculate old and new text length }
oldTextLength = pWE->textLength;
newTextLength = oldTextLength - (rangeEnd - rangeStart);
// { move the end of the text backwards over the old selection range }
pText = (long)(*pWE->hText);
BlockMoveData((Ptr)pText + rangeEnd, (Ptr)pText + rangeStart, oldTextLength - rangeEnd);
// { compact the text handle }
SetHandleSize((Handle)pWE->hText, newTextLength);
err = MemError();
if (err != noErr)
{
goto cleanup2;
}
// { update textLength field }
pWE->textLength = newTextLength;
cleanup1:
// { clear result code }
err = noErr;
cleanup2:
// { return result code }
return err;
}
OSErr _WEInsertText(long offset, Ptr textPtr, long textLength, WEHandle hWE)
{
// { this routine assumes that the WE record is already locked }
WEPtr pWE;
long oldTextLength, newTextLength;
long pInsPoint;
OSErr err;
pWE = *hWE;
// { do nothing if textLength is zero or negative }
if (textLength <= 0)
{
goto cleanup1;
}
// { calculate old and new length of text handle }
oldTextLength = pWE->textLength;
newTextLength = oldTextLength + textLength;
// { leng the raw text handle }
SetHandleSize((Handle)pWE->hText, newTextLength);
err = MemError();
if (err != noErr)
{
goto cleanup2;
}
// { calculate ptr to insertion point }
pInsPoint = (long)(*pWE->hText) + offset;
// { make room for the new text }
BlockMoveData((Ptr)pInsPoint, (Ptr)(pInsPoint + textLength), oldTextLength - offset);
// { insert new text at the insertion point }
BlockMoveData(textPtr, (Ptr)pInsPoint, textLength);
// { update the lineStart fields of all lines following the insertion point }
_WEBumpLineStart(_WEOffsetToLine(offset, hWE) + 1, textLength, pWE);
// { update the runStart fields of all style runs following the insertion point }
_WEBumpRunStart(_WEOffsetToRun(offset - 1, hWE) + 1, textLength, pWE);
// { update various fields in the WE record }
pWE->textLength = newTextLength;
// { if there is a valid null style, apply it to the newly inserted text }
if (BTST(pWE->flags, weFUseNullStyle))
{
err = _WESetStyleRange(offset, offset + textLength, weDoAll + weDoReplaceFace, &pWE->nullStyle.runStyle, hWE);
if (err != noErr)
{
goto cleanup2;
}
}
cleanup1:
// { clear result code }
err = noErr;
cleanup2:
// { return result code }
return err;
}
pascal OSErr WEDelete(WEHandle hWE)
{
WEPtr pWE;
long offset;
// WERunInfo runInfo;
Boolean saveWELock;
OSErr err;
// WEDelete = noErr;
// { lock the WE record }
saveWELock = _WESetHandleLock((Handle)hWE, true);
pWE = *hWE;
offset = pWE->selStart;
// { do nothing if the selection range is empty }
if (offset < pWE->selEnd)
{
// { delete the selection range }
err = _WEDeleteRange(offset, pWE->selEnd, hWE);
if (err != noErr)
{
return err;
}
// { selEnd becomes equal to selStart }
pWE->selEnd = offset;
// { redraw the text }
err = _WERedraw(offset, offset, hWE);
if (err != noErr)
{
return err;
}
} // { if non-empty selection }
// { unlock the WE record }
_WESetHandleLock((Handle)hWE, saveWELock);
return noErr;
}
pascal OSErr WEInsert(Ptr textPtr, long textLength, WEStyleScrapHandle styleScrap, WEHandle hWE)
{
WEPtr pWE;
long offset, endOffset;
Boolean saveWELock;
OSErr err;
// { lock the WE record }
saveWELock = _WESetHandleLock((Handle)hWE, true);
pWE = *hWE;
offset = pWE->selStart;
// { delete current selection }
err = _WEDeleteRange(offset, pWE->selEnd, hWE);
if (err != noErr)
{
goto cleanup;
}
// { insert the new text at the insertion point }
err = _WEInsertText(offset, textPtr, textLength, hWE);
if (err != noErr)
{
goto cleanup;
}
// { move the insertion point at the end of the inserted text }
endOffset = offset + textLength;
pWE->selStart = endOffset;
pWE->selEnd = endOffset;
if (styleScrap != nil)
{
// { if a styleScrap was supplied, apply it to the newly inserted text }
err = _WEApplyStyleScrap(offset, endOffset, styleScrap, hWE);
if (err != noErr)
{
goto cleanup;
}
}
// { invalid the null style }
BCLR(pWE->flags, weFUseNullStyle);
// { redraw the text }
err = _WERedraw(offset, endOffset, hWE);
if (err != noErr)
{
goto cleanup;
}
// { clear result code }
err = noErr;
cleanup:
// { unlock the WE record }
_WESetHandleLock((Handle)hWE, saveWELock);
// { return result code }
return err;
}
void _WEInsertByte(char theByte, WEHandle hWE)
{
WEPtr pWE;
short db;
long charLength;
short byteType;
short saveFont;
GrafPtr savePort;
pWE = *hWE;
charLength = 1; // { assume 1-byte character by default }
db = theByte << 8;
// { delete current selection, if any }
_WEDeleteRange(pWE->selStart, pWE->selEnd, hWE);
pWE->selEnd = pWE->selStart;
// { make sure the font script is synchronized with the keyboard script }
_WESynchNullStyle(hWE);
if (BTST(pWE->flags, weFDoubleByte))
{
// { special processing for double-byte characters }
if (pWE->firstByte != 0)
{
// { if this byte is the second half of a double-byte character, }
// { insert the two bytes at the same time (flush the double-byte cache) }
db = pWE->firstByte << 8 + theByte;
charLength = 2;
pWE->firstByte = 0;
}
else
{
// { determine the byte-type of theByte; first set up the port and its font }
GetPort(&savePort);
SetPort(pWE->port);
saveFont = pWE->port->txFont;
TextFont(pWE->nullStyle.runStyle.tsFont);
// { call CharByte }
byteType = CharByte(&theByte, 0);
// { put back font and port }
TextFont(saveFont);
SetPort(savePort);
// { if theByte is the first half of a double-byte character, just cache it and exit }
if (byteType == smFirstByte)
{
pWE->firstByte = theByte;
return;
}
}
} // { if double-byte script installed }
// { insert the new character into the text }
WEInsert((char *)&db, charLength, nil, hWE);
}
void _WEBackspace(WEHandle hWE)
{
// { this routine is called by WEKey to handle the backspace key }
// { the WE record is guaranteed to be already locked }
WEPtr pWE;
long offset, charLength;
OSErr err;
pWE = *hWE;
offset = pWE->selStart;
// { if the selection range is not empty, delete the current selection range }
if (offset < pWE->selEnd)
{
err = _WEDeleteRange(offset, pWE->selEnd, hWE);
}
else
{
// { do nothing if insertion point is at the beginning of the text }
if (offset <= 0)
{
return;
}
// { determine the byte-type of the character preceding the insertion point }
if (WECharByte(offset - 1, hWE) == smSingleByte)
{
charLength = 1;
}
else
{
charLength = 2;
}
// { delete the character }
offset = offset - charLength;
err = _WEDeleteRange(offset, offset + charLength, hWE);
}
// { keep track of current selection range }
pWE->selStart = offset;
pWE->selEnd = offset;
// { redraw the text }
err = _WERedraw(offset, offset, hWE);
}
pascal void WEKey(short key, short modifiers, WEHandle hWE)
{
WEPtr pWE;
Boolean saveWELock;
// { lock the WE record }
saveWELock = _WESetHandleLock((Handle)hWE, true);
pWE = *hWE;
// { hide the caret if it's showing }
if (BTST(pWE->flags, weFCaretVisible))
{
_WEDrawCaret(hWE);
}
// { hide the cursor (it will show again as soon as it's moved) }
ObscureCursor();
// { dispatch on key class (arrow keys, printable characters, backspace) }
if ((key >= kArrowLeft) && (key <= kArrowDown))
{
_WEDoArrowKey(key, modifiers, hWE);
}
else if (key == kBackspace)
{
_WEBackspace(hWE);
}
else
{
_WEInsertByte(key, hWE);
}
// { unlock the WE record }
_WESetHandleLock((Handle)hWE, saveWELock);
}
pascal OSErr WECut(WEHandle hWE)
{
OSErr err;
// WECut = noErr;
// { Cut is just Copy + Delete }
err = WECopy(hWE);
if (err != noErr)
{
return err;
}
err = WEDelete(hWE);
if (err != noErr)
{
return err;
}
return noErr;
}
pascal OSErr WESetStyle(short mode, WETextStyle *ts, WEHandle hWE)
{
WEPtr pWE;
ScriptCode fontScript;
Boolean saveWELock;
OSErr err;
// { lock the WE record }
saveWELock = _WESetHandleLock((Handle)hWE, true);
pWE = *hWE;
// { if the selection range is empty, set the null style }
if (pWE->selStart == pWE->selEnd)
{
// { first make sure the nullStyle field contains valid information }
_WESynchNullStyle(hWE);
// { apply style changes to the nullStyle record }
_WECopyStyle(ts, &pWE->nullStyle.runStyle, pWE->nullStyle.runStyle.tsFace, mode);
// { if the font was altered, synchronize the keyboard script }
if (BTST(pWE->flags, weFNonRoman))
{
if (BTST(mode, kModeFont))
{
fontScript = Font2Script(pWE->nullStyle.runStyle.tsFont);
if (fontScript != GetEnvirons(smKeyScript))
{
KeyScript(fontScript);
}
}
}
}
else
{
// { otherwise set the style of the selection range }
err = _WESetStyleRange(pWE->selStart, pWE->selEnd, mode, ts, hWE);
if (err != noErr)
{
goto cleanup;
}
// { and redraw the text }
err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
if (err != noErr)
{
goto cleanup;
}
}
// { clear the result code }
err = noErr;
cleanup:
// { unlock the WE record }
_WESetHandleLock((Handle)hWE, saveWELock);
// { return result code }
return err;
}
pascal OSErr WEUseStyleScrap(WEStyleScrapHandle styleScrap, WEHandle hWE)
{
WEPtr pWE;
Boolean saveWELock;
OSErr err;
// { lock the WE record }
saveWELock = _WESetHandleLock((Handle)hWE, true);
pWE = *hWE;
// { apply the style scrap to the selection range }
err = _WEApplyStyleScrap(pWE->selStart, pWE->selEnd, styleScrap, hWE);
if (err != noErr)
{
goto cleanup;
}
// { redraw the text }
err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
cleanup:
// { unlock the WE record }
_WESetHandleLock((Handle)hWE, saveWELock);
// { return result code }
return err;
}
pascal OSErr WEPaste(WEHandle hWE)
{
Handle hText, hStyles;
long scrapResult, scrapOffset;
OSErr err;
hText = nil;
hStyles = nil;
// { allocate a handle to hold the text }
err = _WEAllocate(0, kAllocTemp, (Handle *)&hText);
if (err != noErr)
{
goto cleanup;
}
// { look for a 'TEXT' item }
scrapResult = GetScrap(hText, kTypeText, &scrapOffset);
if (scrapResult <= 0)
{
err = scrapResult;
goto cleanup;
}
// { allocate a handle to hold the style scrap }
err = _WEAllocate(0, kAllocTemp, (Handle *)&hStyles);
if (err != noErr)
{
goto cleanup;
}
// { look for a 'styl' item accompanying the text }
scrapResult = GetScrap(hStyles, kTypeStyles, &scrapOffset);
// { forget the handle if nothing was found or an error occurred }
if (scrapResult <= 0)
{
_WEForgetHandle((Handle *)&hStyles);
}
// { lock down the text }
HLock(hText);
// { insert the text }
err = WEInsert(*hText, GetHandleSize(hText), (WEStyleScrapHandle)hStyles, hWE);
cleanup:
// { clean up }
_WEForgetHandle((Handle *)&hText);
_WEForgetHandle((Handle *)&hStyles);
// { return result code }
return err;
}